package edu.the.last.audio;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.TargetDataLine;

import edu.the.last.Messages;
import edu.the.last.modell.Music;

/**
 * 
 * @author albertcsani
 * 
 *         Reads data from the input channel and writes to the output stream
 */
public class Capture implements Runnable {

	private TargetDataLine line;
	private Thread thread;
	private Music music;
	private DataLine.Info info;

/**
 *  Constructor
 * @param music the Music object witch will be filled whit data
 */
	public Capture(Music music) {
		this.music = music;
		info = new DataLine.Info(TargetDataLine.class, music.getFormat());
		thread = new Thread(this);
		thread.setName(Messages.getString("Capture.Capture")); //$NON-NLS-1$
		if (!AudioSystem.isLineSupported(info)) {
			shutDown(Messages.getString("Capture.Line") + info + Messages.getString("Capture.NotSuported")); //$NON-NLS-1$ //$NON-NLS-2$
			return;
		}
	}

	/**
	 * start the recording
	 */
	public void start() {
		thread.start();
	}

	/**
	 * stop the recording
	 */
	public void stop() {
		thread = null;
	}

	/**
	 * stops the recording in case of an error
	 * 
	 * @param message
	 */
	private void shutDown(String message) {
		if (message != null && thread != null) {
			thread = null;
			try {
				throw new Exception(message);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * the real recording....
	 */
	public void run() {
		// get and open the target data line for capture.
		try {
			line = (TargetDataLine) AudioSystem.getLine(info);
			line.open( music.getFormat(), line.getBufferSize());
		} catch (LineUnavailableException ex) {
			shutDown(Messages.getString("Capture.UnabableToOpen") + ex); //$NON-NLS-1$
			return;
		} catch (Exception ex) {
			shutDown(ex.toString());
			return;
		}
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		int frameSizeInBytes =  music.getFormat().getFrameSize();
		int bufferLengthInFrames = line.getBufferSize() / 8;
		int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes;
		byte[] data = new byte[bufferLengthInBytes];
		int numBytesRead;
		line.start();
		while (thread != null) {
			if ((numBytesRead = line.read(data, 0, bufferLengthInBytes)) == -1) {
				break;
			}
			out.write(data, 0, numBytesRead);
		}

		// end of stream
		line.stop();
		line.close();
		line = null;

		// stop and close the output stream
		try {
			out.flush();
			out.close();
		} catch (IOException ex) {
			ex.printStackTrace();
		}

		byte audioBytes[] = out.toByteArray();
		music.setAudioBytes(audioBytes);
	}
}